'''Transponiere Matrix und vergleiche die Zeilen und Spaltensumme.
Copyright (C) 2012 Thomas Nauss

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Please send any comments, suggestions, criticism, or (for our sake) bug
reports to nausst@googlemail.com
'''

__author__ = "Thomas Nauss <nausst@googlemail.com>"
__version__ = "2012-12-07"
__license__ = "GNU GPL, see http://www.gnu.org/licenses/"

import csv
import numpy


def matrix_input(filename, delimiter=";"):
    '''Funktion zum Lesen von CSV-Dateien
    Beim einlesen der CSV-Werte werden alle Werte, die nicht als String
    identifiziert werden in Datentypen fuer Gleitkommazahlen umgewandelt.
    
    Args:
        filename: Pfad und Name der Eingabedatei
        delimiter: Trennzeichen fuer Spalten

    Returns:
        Liste mit Inhalt der CSV-Datei

    '''
    csvfile = open(filename)
    csv_content = csv.reader(csvfile, delimiter=delimiter, \
                             quoting=csv.QUOTE_NONNUMERIC)
    data_list = []
    for row in csv_content:
        data_list.append(row)
    return data_list

    
def row_col_sum(dataset):
    '''Funktion zum Berechnen der Zeilen und Spaltensummen
    Die Zeilensummen werden einfach aufsummiert. Fuer die Spaltensummen wird
    zunaechst eine Liste der Laenge der Anzahl der Spalten angelegt und dann
    an der einer Spalte entsprechenden Listenposition die Spaltensumme
    schrittweise berechnet.
    
    Args:
        dataset: Datensatz, dessen Summen berechnet werden sollen

    Returns:
        2 Listen mit den Zeilensummen und Spaltensummen

    '''
    sum_rows = []
    sum_cols = [0] * len(dataset[0])
    for row in dataset:
        sum_row = 0
        for col_number in range(0, len(row)):
            sum_cols[col_number] = sum_cols[col_number] + row[col_number]        
            sum_row = sum_row + row[col_number]
        sum_rows.append(sum_row)
    return sum_rows, sum_cols

    
def transpose(dataset):
    '''Funktion zum Vertauschen der Zeilen und Spalten einer Listenmatrix
    Die Funktion erstellt zunaechst eine neue, leere Liste mit der Dimension
    der transponierten Matrix und fuellt diese dann durch einfaches vertauschen
    des Zeilen-/Spaltenindex.
    
    Args:
        dataset: Datensatz, dessen Zeilen und Spalten vertauscht werden sollen

    Returns:
        Zeilen- und Spaltenvertauschten Datensatz

    '''
    transposed = []
    for icol in range(0, len(dataset[0])):
        transposed.append([0]*len(dataset))
    
    for irow in range(0, len(dataset)):
        for icol in range(0, len(dataset[0])):
            transposed[icol][irow] = dataset[irow][icol]
    return transposed
    
    
def ausgabe(dataset, title=None, row_info=None, col_info=None):
    '''Funktion zum Ausschreiben einer Matrix auf die Kommandozeile.
    Neben der Matrix kann eine Information fuer jede Spalte und Zeile sowie ein
    Titel angegeben werden.
   
    Der Titel und die Zeilen-/Spalten-Informationen werden nur ausgegeben, wenn
    die Eingangsvariablen nicht leer sind.
    
    Args:
        dataset: Datensatz, der ausgegeben werden soll
        title: Titel des Datensatzes
        row_info: Informationen, die am Ende jeder Zeile angezeit werden sollen
                  (die Laenge der Variablen ist die Anzahl der Matrix-Zeilen)
        col_info: Informationen, die am Ende jeder Zeile angezeit werden sollen
                  (die Laenge der Variablen ist die Anzahl der Matrix-Spalten)
    '''
    # Ausgabe des Titels
    if title != None:
        print
        print title
    
    # Ausgabe der Matrix sowie ggf. der Zeileninformationen am Ende jeder Zeile
    space = 5
    joiner = '  '
    irow = 0
    for row in dataset:
        output = []
        for col in row:
            output.append(str(col).rjust(space))
        if row_info != None:
            output.append("| " + str(row_info[irow]).rjust(space))
        print joiner.join(output)
        irow = irow + 1
    
    # Ausgabe der Spalteninformationen
    if col_info != None:
        output = []
        for item in col_info:
            output.append(str(item).rjust(space))
        print '-' * len(joiner.join(output))
        print joiner.join(output)
    print

    
if __name__ == "__main__":  
    '''Diese Anweisung kann weggelassen werden, aber dann koennen die Funktionen
    nicht von extern als Modul aufgerufen werden.
    Insgesamt muss angemerkt werden, dass bei Verwendung der numpy-Bibliothek
    die oben definierten Funktionen fast alle ueberfluessig waeren.
    '''
    print    
    print
    print "Modul matrix zum Transponieren einer Matrix"
    print
    print __author__
    print __version__
    print __license__
    print
    
    print "Reading matrix data..."
    in_matrix = matrix_input("matrix_org.csv")
    
    print "Computing row and column sums of original matrix..."
    sum_row_org, sum_col_org = row_col_sum(in_matrix)
    
    print "Transposing matrix..."
    out_matrix = transpose(in_matrix)
    
    print "Computing row and column sums of transposed matrix..."
    sum_row_out, sum_col_out = row_col_sum(out_matrix)
    
    ausgabe(in_matrix, "Eingabe-Matrix", sum_row_org, sum_col_org)
    ausgabe(out_matrix, "Ausgabe-Matrix", sum_row_out, sum_col_out)
    
    # Test ob die neuen Spalten-/Zeilensummen groesser sind als fuer die
    # Originaldaten und Ausgabe der Information
    for irow in range(0, len(out_matrix)):
        if sum_row_out[irow] > sum_row_org[irow]:
            print "Reihe " + str(irow+1) + " ist nach Transformation groesser"
        else:
            print "Reihe " + str(irow+1) + " ist nach Transformation kleiner"
    for icol in range(0, len(in_matrix[0])):
        if sum_col_out[icol] > sum_col_org[icol]:
            print "Spalte " + str(icol+1) + " ist nach Transformation groesser"
        else:
            print "Spalte " + str(icol+1) + " ist nach Transformation kleiner"
    print
    print "...finished."